package com.uniflow.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uniflow.common.PageResult;
import com.uniflow.entity.Form;
import com.uniflow.entity.FormData;
import com.uniflow.mapper.FormDataMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 表单数据服务类
 */
@Service
@Transactional
public class FormDataService extends ServiceImpl<FormDataMapper, FormData> {
    
    @Autowired
    private FormDataMapper formDataMapper;
    
    @Autowired
    private UniflowFormService formService;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 分页查询表单数据列表
     */
    public PageResult<FormData> getFormDataList(int pageNum, int pageSize, String formId, 
                                                String businessKey, String processInstanceId, 
                                                String taskId, String status, String submittedBy, 
                                                String reviewedBy, LocalDateTime startDate, 
                                                LocalDateTime endDate) {
        Page<FormData> page = new Page<>(pageNum, pageSize);
        IPage<FormData> result = formDataMapper.selectFormDataPage(page, formId, businessKey, 
                processInstanceId, taskId, status, submittedBy, reviewedBy, startDate, endDate);
        
        // 解析JSON字段
        result.getRecords().forEach(this::parseJsonFields);
        
        return new PageResult<FormData>(pageNum, pageSize, result.getTotal(), result.getRecords());
    }
    
    /**
     * 根据ID查询表单数据详情
     */
    public FormData getFormDataById(String id) {
        FormData formData = this.getById(id);
        if (formData != null) {
            parseJsonFields(formData);
            // 加载关联的表单信息
            if (StringUtils.hasText(formData.getFormId())) {
                Form form = formService.getFormById(formData.getFormId());
                formData.setForm(form);
            }
        }
        return formData;
    }
    
    /**
     * 根据表单ID和业务键查询表单数据
     */
    public FormData getFormDataByFormIdAndBusinessKey(String formId, String businessKey) {
        FormData formData = formDataMapper.selectByFormIdAndBusinessKey(formId, businessKey);
        if (formData != null) {
            parseJsonFields(formData);
        }
        return formData;
    }
    
    /**
     * 根据流程实例ID查询表单数据列表
     */
    public List<FormData> getFormDataByProcessInstanceId(String processInstanceId) {
        List<FormData> formDataList = formDataMapper.selectByProcessInstanceId(processInstanceId);
        formDataList.forEach(this::parseJsonFields);
        return formDataList;
    }
    
    /**
     * 根据任务ID查询表单数据
     */
    public FormData getFormDataByTaskId(String taskId) {
        FormData formData = formDataMapper.selectByTaskId(taskId);
        if (formData != null) {
            parseJsonFields(formData);
        }
        return formData;
    }
    
    /**
     * 根据提交人查询表单数据列表
     */
    public List<FormData> getFormDataBySubmittedBy(String submittedBy, String status) {
        List<FormData> formDataList = formDataMapper.selectBySubmittedBy(submittedBy, status);
        formDataList.forEach(this::parseJsonFields);
        return formDataList;
    }
    
    /**
     * 提交表单数据
     */
    public FormData submitFormData(FormData formData) {
        // 验证表单是否存在且已发布
        Form form = formService.getFormById(formData.getFormId());
        if (form == null) {
            throw new RuntimeException("表单不存在");
        }
        if (!Boolean.TRUE.equals(form.getPublished())) {
            throw new RuntimeException("表单未发布");
        }
        if (!Boolean.TRUE.equals(form.getEnabled())) {
            throw new RuntimeException("表单已禁用");
        }
        
        // 验证表单数据
        validateFormData(formData, form);
        
        // 设置默认值
        if (!StringUtils.hasText(formData.getId())) {
            formData.setId(UUID.randomUUID().toString());
        }
        formData.setFormName(form.getName());
        formData.setFormVersion(form.getVersion());
        formData.setSubmittedAt(LocalDateTime.now());
        
        if (!StringUtils.hasText(formData.getStatus())) {
            formData.setStatus("submitted");
        }
        
        // 序列化JSON字段
        serializeJsonFields(formData);
        
        this.save(formData);
        return formData;
    }
    
    /**
     * 保存草稿
     */
    public FormData saveDraft(FormData formData) {
        // 验证表单是否存在
        Form form = formService.getFormById(formData.getFormId());
        if (form == null) {
            throw new RuntimeException("表单不存在");
        }
        
        // 设置默认值
        if (!StringUtils.hasText(formData.getId())) {
            formData.setId(UUID.randomUUID().toString());
        }
        formData.setFormName(form.getName());
        formData.setFormVersion(form.getVersion());
        formData.setStatus("draft");
        
        // 序列化JSON字段
        serializeJsonFields(formData);
        
        this.saveOrUpdate(formData);
        return formData;
    }
    
    /**
     * 更新表单数据
     */
    public FormData updateFormData(FormData formData) {
        FormData existingFormData = this.getById(formData.getId());
        if (existingFormData == null) {
            throw new RuntimeException("表单数据不存在");
        }
        
        // 只有草稿状态的数据才能更新
        if (!"draft".equals(existingFormData.getStatus())) {
            throw new RuntimeException("只有草稿状态的表单数据才能更新");
        }
        
        // 验证表单数据
        Form form = formService.getFormById(formData.getFormId());
        if (form != null) {
            validateFormData(formData, form);
        }
        
        // 序列化JSON字段
        serializeJsonFields(formData);
        
        this.updateById(formData);
        return formData;
    }
    
    /**
     * 删除表单数据
     */
    public void deleteFormData(String id) {
        FormData formData = this.getById(id);
        if (formData == null) {
            throw new RuntimeException("表单数据不存在");
        }
        
        // 只有草稿状态的数据才能删除
        if (!"draft".equals(formData.getStatus())) {
            throw new RuntimeException("只有草稿状态的表单数据才能删除");
        }
        
        this.removeById(id);
    }
    
    /**
     * 批量删除表单数据
     */
    public void batchDeleteFormData(List<String> ids) {
        for (String id : ids) {
            deleteFormData(id);
        }
    }
    
    /**
     * 审核表单数据
     */
    public void reviewFormData(String id, String status, String reviewComment, 
                              String reviewedBy, String reviewedByName) {
        FormData formData = this.getById(id);
        if (formData == null) {
            throw new RuntimeException("表单数据不存在");
        }
        
        if (!"submitted".equals(formData.getStatus()) && !"processing".equals(formData.getStatus())) {
            throw new RuntimeException("只有已提交或处理中的表单数据才能审核");
        }
        
        if (!"approved".equals(status) && !"rejected".equals(status)) {
            throw new RuntimeException("审核状态只能是approved或rejected");
        }
        
        formDataMapper.updateStatus(id, status, reviewedBy, reviewedByName, reviewComment);
    }
    
    /**
     * 批量审核表单数据
     */
    public void batchReviewFormData(List<String> ids, String status, String reviewComment, 
                                   String reviewedBy, String reviewedByName) {
        if (!"approved".equals(status) && !"rejected".equals(status)) {
            throw new RuntimeException("审核状态只能是approved或rejected");
        }
        
        formDataMapper.batchUpdateStatus(ids, status, reviewedBy, reviewedByName, reviewComment);
    }
    
    /**
     * 更新表单数据状态
     */
    public void updateFormDataStatus(String id, String status) {
        FormData formData = this.getById(id);
        if (formData == null) {
            throw new RuntimeException("表单数据不存在");
        }
        
        formDataMapper.updateStatus(id, status, null, null, null);
    }
    
    /**
     * 检查业务键是否存在
     */
    public boolean isBusinessKeyExists(String businessKey, String excludeId) {
        return formDataMapper.checkBusinessKeyExists(businessKey, excludeId) > 0;
    }
    
    /**
     * 获取表单数据统计信息
     */
    public Map<String, Object> getFormDataStatistics(String formId) {
        return formDataMapper.getFormDataStatistics(formId);
    }
    
    /**
     * 根据表单统计数据量
     */
    public List<Map<String, Object>> getFormDataCountByForm(Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        return formDataMapper.getFormDataCountByForm(limit);
    }
    
    /**
     * 根据状态统计数据量
     */
    public List<Map<String, Object>> getFormDataCountByStatus(String formId) {
        return formDataMapper.getFormDataCountByStatus(formId);
    }
    
    /**
     * 根据提交人统计数据量
     */
    public List<Map<String, Object>> getFormDataCountBySubmitter(String formId, Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        return formDataMapper.getFormDataCountBySubmitter(formId, limit);
    }
    
    /**
     * 根据时间统计数据量
     */
    public List<Map<String, Object>> getFormDataCountByDate(String formId, 
                                                           LocalDateTime startDate, 
                                                           LocalDateTime endDate) {
        return formDataMapper.getFormDataCountByDate(formId, startDate, endDate);
    }
    
    /**
     * 根据时间统计数据量（按月）
     */
    public List<Map<String, Object>> getFormDataCountByMonth(String formId, 
                                                            LocalDateTime startDate, 
                                                            LocalDateTime endDate) {
        return formDataMapper.getFormDataCountByMonth(formId, startDate, endDate);
    }
    
    /**
     * 获取待处理的表单数据数量
     */
    public int getPendingFormDataCount(String assignee) {
        return formDataMapper.getPendingFormDataCount(assignee);
    }
    
    /**
     * 获取我的表单数据统计
     */
    public Map<String, Object> getMyFormDataStatistics(String userId) {
        return formDataMapper.getMyFormDataStatistics(userId);
    }
    
    /**
     * 根据表单ID删除所有相关数据
     */
    public void deleteFormDataByFormId(String formId) {
        formDataMapper.deleteByFormId(formId);
    }
    
    /**
     * 根据流程实例ID删除表单数据
     */
    public void deleteFormDataByProcessInstanceId(String processInstanceId) {
        formDataMapper.deleteByProcessInstanceId(processInstanceId);
    }
    
    /**
     * 解析JSON字段
     */
    private void parseJsonFields(FormData formData) {
        try {
            if (StringUtils.hasText(formData.getDataJson())) {
                Map<String, Object> data = objectMapper.readValue(
                        formData.getDataJson(), new TypeReference<Map<String, Object>>() {});
                formData.setData(data);
            }
        } catch (Exception e) {
            // 忽略JSON解析错误
        }
    }
    
    /**
     * 序列化JSON字段
     */
    private void serializeJsonFields(FormData formData) {
        try {
            if (formData.getData() != null) {
                formData.setDataJson(objectMapper.writeValueAsString(formData.getData()));
            }
        } catch (Exception e) {
            throw new RuntimeException("序列化表单数据JSON字段失败", e);
        }
    }
    
    /**
     * 验证表单数据
     */
    private void validateFormData(FormData formData, Form form) {
        if (formData.getData() == null || formData.getData().isEmpty()) {
            throw new RuntimeException("表单数据不能为空");
        }
        
        if (form.getFields() != null) {
            for (Form.FormField field : form.getFields()) {
                // 验证必填字段
                if (Boolean.TRUE.equals(field.getRequired())) {
                    Object value = formData.getData().get(field.getName());
                    if (value == null || (value instanceof String && !StringUtils.hasText((String) value))) {
                        throw new RuntimeException("字段 " + field.getLabel() + " 不能为空");
                    }
                }
                
                // 验证字段长度
                Object value = formData.getData().get(field.getName());
                if (value instanceof String) {
                    String strValue = (String) value;
                    if (field.getMaxLength() != null && strValue.length() > field.getMaxLength()) {
                        throw new RuntimeException("字段 " + field.getLabel() + " 长度不能超过 " + field.getMaxLength());
                    }
                    if (field.getMinLength() != null && strValue.length() < field.getMinLength()) {
                        throw new RuntimeException("字段 " + field.getLabel() + " 长度不能少于 " + field.getMinLength());
                    }
                }
                
                // 验证正则表达式
                if (StringUtils.hasText(field.getPattern()) && value instanceof String) {
                    String strValue = (String) value;
                    if (StringUtils.hasText(strValue) && !strValue.matches(field.getPattern())) {
                        String errorMessage = StringUtils.hasText(field.getErrorMessage()) ? 
                                field.getErrorMessage() : "字段 " + field.getLabel() + " 格式不正确";
                        throw new RuntimeException(errorMessage);
                    }
                }
            }
        }
    }
    
    /**
     * 导出表单数据
     */
    public List<Map<String, Object>> exportFormData(String formId, String status, 
                                                    LocalDateTime startDate, LocalDateTime endDate) {
        // 这里可以实现数据导出逻辑
        // 返回格式化后的数据用于导出
        return null;
    }
    
    /**
     * 生成表单数据报表
     */
    public Map<String, Object> generateFormDataReport(String formId, String reportType, 
                                                      LocalDateTime startDate, LocalDateTime endDate) {
        // 这里可以实现报表生成逻辑
        return null;
    }
}